#include <dinput.h>
#include <qvector.h>
#include <qstring.h>
#include "DeviceManager.h"

int DeviceManager::CheckConnectedDevices(LPCDIDEVICEINSTANCE device, void *thisPtr)
{
	DeviceManager *devMgr = (DeviceManager *)thisPtr;
	LPCDIDEVICEINSTANCE dev = (LPCDIDEVICEINSTANCE) malloc(sizeof(DIDEVICEINSTANCE));
	memcpy((void *)dev, device, sizeof(DIDEVICEINSTANCE));
	devMgr->_devices.append(dev);
	return DIENUM_CONTINUE;
}

DeviceManager::DeviceManager(void)
{
	_selectedDeviceIndex = -1;
	_selectedDevice = NULL;
	_api = NULL;
}

void DeviceManager::init() 
{
	HRESULT hr = 0;
	hr = DirectInput8Create(GetModuleHandle(NULL), 
		DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID *)&_api, NULL);

	if (FAILED(hr))
		throw DeviceManagerInitException(hr);

	hr = _api->EnumDevices(DI8DEVCLASS_GAMECTRL, (LPDIENUMDEVICESCALLBACK)DeviceManager::CheckConnectedDevices,
		this, DIEDFL_ATTACHEDONLY);

	if (FAILED(hr))
		throw DeviceManagerInitException(hr);
}

void DeviceManager::select(int devId) 
{
	HRESULT hr;
	IDirectInputDevice8 *device = NULL;

	if (devId >= 0 && devId < _devices.size()) {
		hr = _api->CreateDevice(_devices.at(devId)->guidProduct, &device, NULL);

		if (FAILED(hr)) {
			_selectedDeviceIndex = -1;
			return;
		}
		
		if (_selectedDevice) {
			delete _selectedDevice;
			_selectedDevice = NULL;
		}

		if (device) {
			_selectedDevice = new Joystick(device);

			try {
				_selectedDevice->setupDevice();
			} catch (JoystickSetupException &e) {
				// TODO: Propogate these
				_selectedDeviceIndex = -1;
				delete _selectedDevice;
				_selectedDevice = NULL;
				return; 
			}

			_selectedDeviceIndex = devId;
			connect(_selectedDevice, SIGNAL(axisChanged(int,int)), this, SLOT(onAxisChanged(int,int)));
			connect(_selectedDevice, SIGNAL(keyDown(int)), this, SLOT(onKeyDown(int)));
			connect(_selectedDevice, SIGNAL(keyUp(int)), this, SLOT(onKeyUp(int)));
		}
	}

}

void DeviceManager::pollDevices()
{
	if (_selectedDevice) {
		try {
			_selectedDevice->poll();
		} catch (JoystickPollingException &e) {
			select(_selectedDeviceIndex);
		}
	}
}

int DeviceManager::getGamepadCount()
{ 
	return _devices.size(); 
}
	
QString DeviceManager::getDeviceName(int id) 
{ 
	if (id >= 0 && id < _devices.size())
		return QString::fromUtf16(_devices.at(id)->tszProductName); 

	return QString("Error");
}

DeviceManager::~DeviceManager(void)
{
	if (_api)
		_api->Release();

	if (_selectedDevice) {
		delete _selectedDevice;
		_selectedDevice = NULL;
	}

	for (int i = 0; i < _devices.size(); i++) {
		if (_devices.at(i)) 
			free((void *)_devices.at(i));
	}
}
